# Created by 子沐 at 2019/10/25
#import autoinstall
from app import app,socketio
from app import app,sockets
from util import conf
from time import time
from werkzeug import serving
from flask import request,render_template,jsonify
from time import time
import re
import io
import os
import subprocess
from sqlalchemy.sql import or_,and_
from model import Story,Lesson,Chapter
from util.docker_extend import  ClientHandler, DockerStreamThread, BeatWS
import paramiko
# 首页
@app.route('/')
def index():
    #lesson_list=Lesson.query.all()
    return render_template('editor.html')

# 内容页
@app.route('/story/<int:lesson_id>')
def story(lesson_id):
    lesson_info=Lesson.query.get(lesson_id)
    return render_template('story.html',lesson_id=lesson_id,lesson_info=lesson_info)


# 下一条记录
@app.route('/next/<int:lesson_id>')
def next(lesson_id):
    sort=request.args.get('sort')
    story_item=Story.query.filter(and_(Story.lesson_id==lesson_id,Story.sort==sort)).first()
    if story_item:
        story_data={'Id':story_item.Id,'content':story_item.content,'type':story_item.type,'chapter_id':story_item.chapter_id}
        returnData = {'status': 1, 'data': story_data}
    else:
        story_data={}
        returnData = {'status': 0, 'data': story_data}
    return jsonify(returnData)

# 执行代码
@app.route('/runcode',methods=['POST','GET'])
def runcode():
    if request.method=='POST':
        code = request.json.get('code')
        returnData = {'status': 0}
        if code:
            filename = f'{time()}.py'
            open(filename, 'w').write(code)
            # sftp
            transport = paramiko.Transport(('192.168.5.134', 22))
            transport.connect(username='root', password='123456')
            sftp = paramiko.SFTPClient.from_transport(transport)
            # 将location.py 上传至服务器 /tmp/test.py
            sftp.put(filename, '/root/' + filename)

            returnData['filename'] = filename
            returnData['status'] = 1
            os.remove(filename)
        return jsonify(returnData)
    return render_template('codemirror.html')

@sockets.route('/echo/<string:filename>')
def echo_socket(ws,filename):
    dockerCli = ClientHandler(base_url=conf.DOCKER_HOST, timeout=10)
    container_id=dockerCli.createContainer(conf.DOCKER_IMAGES)
    # ssh
    ssh = paramiko.SSHClient()
    # 允许连接不在know_hosts文件中的主机
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())  # 第一次登录的认证信息
    # 连接服务器
    ssh.connect(hostname='192.168.5.134', port=22, username='root', password='123456')
    cmd = f'docker cp {filename} {container_id}:{filename}'
    ssh.exec_command(cmd)
    terminalExecId = dockerCli.creatTerminalExec(container_id, filename)
    print("docker daemon socket is start")
    terminalStream = dockerCli.startTerminalExec(terminalExecId)._sock

    terminalThread = DockerStreamThread(ws, terminalStream)
    terminalThread.start()
    beat_thread = BeatWS(ws, dockerCli.client)
    beat_thread.start()

    try:
        while not ws.closed:
            message = ws.receive()
            if message is not None:
                sed_msg = bytes(message, encoding='utf-8')
                if sed_msg != b'__ping__':
                    terminalStream.send(bytes(message, encoding='utf-8'))
    except Exception as err:
        print(err)
    finally:
        ws.close()
        ssh.exec_command(f'rm -f {filename}')
        terminalStream.close()
        dockerCli.dockerClient.stop(container_id)
        dockerCli.dockerClient.remove_container(container_id)
        dockerCli.dockerClient.close()

# 执行代码
@app.route('/admin',methods=['POST','GET'])
def admin():
    if request.method=='POST':
        code=request.json.get('code','')
        filename=str(time())+'.py'
        f=open(filename,'w',encoding='utf-8')
        f.write(code)
        f.close()
        retunData={'status':1}
        # 执行命令
        CMD=f'python {filename}'
        proc = subprocess.Popen(CMD, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, bufsize=-1)

        stream_stdout = io.TextIOWrapper(proc.stdout, encoding='utf-8')
        stream_stderr = io.TextIOWrapper(proc.stderr, encoding='utf-8')

        # 输出和错误
        str_stdout = str(stream_stdout.read())
        str_stderr = str(stream_stderr.read())
        if str_stderr:
            re_com=re.compile('[\d\D]*(line\s\d)[\d\D]*?(\w*(?:Error|Exception).*)')
            matchArr=re_com.findall(str_stderr)
            retunData['status']=0
            retunData['msg']=','.join(matchArr[0])
        retunData['out']=str_stdout
        os.remove(filename)
        return jsonify(retunData)
    return render_template('codemirror.html')

# 获取课程章节
@app.route('/get/chapter/list/<int:lesson_id>')
def get_chapter_list(lesson_id):
    returnData={'status':1}
    chapter_obj_list=Chapter.query.filter(and_(Chapter.lesson_id==lesson_id,Chapter.pId==0)).all()
    if chapter_obj_list:
        returnData['data']=[{'Id':chapter_item.Id,'name':chapter_item.name,'children':[{'Id':item.Id,'name':item.name} for item in chapter_item.child_chapter]} for chapter_item in chapter_obj_list]
    else:
        returnData['status']=0
    return jsonify(returnData)


# 获取练习题
@app.route('/practice/<int:id>')
def practice(id):
    practice_info=Practice.query.get(id)
    return render_template('practice.html',practice_info=practice_info)

socketio.run(app,host='0.0.0.0',debug=True,port=5050)